package be.ac.ulb.mlg.utils.measure.kernel;


/*
 * The MIT License (MIT)
 * 
 * Copyright (c) 2013 Jean-Sebastien Lerat (Jean-Sebastien.Lerat@ulb.ac.be)
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

/**
 * 
 * @author Jean-Sebastien Lerat (Jean-Sebastien.Lerat@ulb.ac.be)
 * @version 1.00, 30/08/2013
 * @see http://crsouza.blogspot.be/2010/03/kernel-functions-for-machine-learning.html
 */

import be.ac.ulb.mlg.utils.measure.Kernel;

import static java.lang.Math.exp;

public class GaussianKernel implements Kernel{
	protected double multiplicator;
	
	@Override
	/**
	 * Compute the kernel function on x,y using the norm 2 ( exp ( || x - y || * multiplicator))
	 * where the multiplicator is defined in the setup function. By default : -1/(2 sigma^2)
	 */
	public double ker(final double x,final double y) {
		// exp(-gamma x || x - y ||^2) <=> exp( - || x - y ||^2 / (2 * sigma ^ 2) )
		// for norm x must by divided by two but in the equation, we take the squared value
		//=> sqrt(x)^2 = x
		return exp(multiplicator * (x * x + y * y));
	}

	@Override
	/**
	 * Setup the Gaussian kernel by seting the multiplicator as -1 / (2 * sigma ^ 2)
	 */
	public void setup(double[] data,final boolean hasMissing) {
		double excpectation = 0.0, sigmasquare = 0.0;
		int n = data.length;
		if(hasMissing){
			for(int i=0;i<data.length;i++)
				if(Double.isNaN(data[i])) n--;
				else{
					excpectation	+= data[i];
					sigmasquare		+= data[i]*data[i];
				}
		}else{
			for(double d:data){
				excpectation	+= d;
				sigmasquare		+= d*d;
			}
		}
		sigmasquare	= (sigmasquare - excpectation*excpectation)/n;
		multiplicator = - 1.0  / (2.0 * sigmasquare);
	}

}
